package org.jackysoft.service.impl;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.annotation.Resource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.hibernate.Query;
import org.jackysoft.entity.ArmDailyProductReporter;
import org.jackysoft.entity.ArmItem;
import org.jackysoft.entity.CollationDailyReport;
import org.jackysoft.entity.DailyResetDate;
import org.jackysoft.entity.DataItem;
import org.jackysoft.entity.Department;
import org.jackysoft.entity.MonthPlanning;
import org.jackysoft.entity.MonthPlanningItem;
import org.jackysoft.entity.OfficeDocument;
import org.jackysoft.entity.Product;
import org.jackysoft.entity.ProductType;
import org.jackysoft.entity.User;
import org.jackysoft.report.ArmItemRegionEqualsPredicate;
import org.jackysoft.report.DataItemType;
import org.jackysoft.report.ReportConstant;
import org.jackysoft.report.ReportException;
import org.jackysoft.report.rows.ArmItemResearchRowWatcher;
import org.jackysoft.report.rows.converter.EvaluateFormulaConverter;
import org.jackysoft.report.rows.converter.ResearchRowConverter;
import org.jackysoft.report.rows.converter.RowConverter;
import org.jackysoft.report.visitor.ArmItemFinalStoreDailyVisitor;
import org.jackysoft.report.visitor.ArmItemVisitor;
import org.jackysoft.service.AbstractReportServiceImpl;
import org.jackysoft.service.ArmDailyReporterService;
import org.jackysoft.service.ArmMonthlyPlanService;
import org.jackysoft.service.DailyResetDateService;
import org.jackysoft.service.NewsInfoService;
import org.jackysoft.util.AttachmentType;
import org.jackysoft.util.CollectionUtils;
import org.jackysoft.util.FileInfo;
import org.jackysoft.util.IOUtils;
import org.jackysoft.util.Page;
import org.jackysoft.util.RowWatcher;
import org.jackysoft.util.SOAOfficeUtil;
import org.jackysoft.util.SpringSecurityUtils;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.itextpdf.text.DocumentException;

@Service
@Transactional
public class ArmDailyReporterServiceImpl extends
		AbstractReportServiceImpl<ArmDailyProductReporter> implements
		ArmDailyReporterService {

	private static final Log logger = LogFactory
			.getLog(ArmDailyReporterServiceImpl.class);
	/**
	 * 
	 */
	private static final long serialVersionUID = 5066753257576485925L;

	private NewsInfoService newsService;
	@Value("${daily.catalogId}")
	private String dailyCatalogId;

	private ArmMonthlyPlanService planningService;

	private ArmItemFinalStoreDailyVisitor finalStoreVistor;

	private DailyResetDateService resetDateService;
	
	
	private ArmItemRegionEqualsPredicate regionPredicate;
	
	
	public ArmDailyReporterServiceImpl() {
		super(ArmDailyProductReporter.class);
	}

	@Override
	public void update(ArmDailyProductReporter t) throws DataAccessException {

		ArmDailyProductReporter at = get(t.getId());
      
		if (at.isFinished()) {
			logger.warn("报表 " + at.getId() + " 已经提交,不能再次修改");
			return;
		}
		ArmDailyProductReporter last = at.getLast();

		at.setUpdateDate(DateTime.now());
		at.setDepartment(t.getDepartment());
		at.setLeader(t.getLeader());
		at.setMaker(t.getMaker());
		at.setLast(last);
		at.getArmItems().clear();
		at.getArmItems().addAll(t.getArmItems());
		updateAccumulate(at, last);
		updateDailyStore(at);
		super.update(at);
	}

	@Override
	public void create(ArmDailyProductReporter t) throws DataAccessException {
		User user = SpringSecurityUtils.getCurrentUser();
		Department dept = user.getDepartment();
		DateTime dt = DateTime.now();
		ArmDailyProductReporter temp = get(dt, dept);
		if(temp!=null) return;
		String lastId = getLast(dept);		
		ArmDailyProductReporter last = get(lastId);
		updateAccumulate(t, last);
		updateDailyStore(t);
		t.setLast(last);
		t.setCreateDate(dt);
		super.create(t);

	}	
	
	@Override
	public String getLast(Department department) throws DataAccessException {
		String hql = String
				.format("select r.id from %s r where r.department.id='%s' and  " +
						"r.createDate=(select max(t.createDate) from %s t " +
						"where t.department.id='%s'" +
						" and datediff(date(t.createDate),CURRENT_DATE)<0)",
						table(), department.getId(), table(),
						department.getId());
        logger.info(hql);
		Iterator itr = query(hql).iterate();
		return (String) (itr.hasNext() ? itr.next() : null);
	}

	
	@Override
	public void remove(ArmDailyProductReporter t) throws DataAccessException {
		
		ArmDailyProductReporter rpt = get(t.getId());
		if(rpt.isFinished()) return;
		String hql = String.format(
				"update %s r set r.last=null where r.last.id='%s'",
				table(), t.getId());
		query(hql).executeUpdate();
		
		super.remove(rpt);
	}

	
	
	@Override
	protected void updateAccumulate(ArmDailyProductReporter t,
			ArmDailyProductReporter last) {
		DateTime di = DateTime.now();		
        boolean resetable = this.resetable(di);
        if(!resetable) 
        	accumulate(t, last);
        else
        	accumulate(t, null);
	}

	protected void accumulate(ArmDailyProductReporter t,ArmDailyProductReporter last){
		if (last == null) {
			last = emptyReport();
		}
		Map<ProductType, Collection<ArmItem>> items = dataItemUtil
				.mergeArmItemMap(t.getArmItems());
		Map<ProductType, Collection<ArmItem>> lastItems = dataItemUtil
				.mergeArmItemMap(last.getArmItems());
		List<ArmItem> litems = Lists.newArrayList();
		for (Map.Entry<ProductType, Collection<ArmItem>> itemEntry : items
				.entrySet()) {
			Collection<ArmItem> typedItems = itemEntry.getValue();
			Collection<ArmItem> lastTypedItems   = lastItems.get(itemEntry.getKey());
			for (ArmItem item : typedItems) {
				if (item == null)
					continue;
				regionPredicate.init(item, itemEntry.getKey());				
				ArmItem src = (ArmItem) CollectionUtils.find(lastTypedItems,regionPredicate);
				accumulateVisitor.setSource(src);
				item.accetp(accumulateVisitor);
			}
			litems.addAll(typedItems);
		}		
		t.getArmItems().clear();
		t.getArmItems().addAll(litems);
	}
	
	
	@Override
	public byte[] getResearchBytes(String id, boolean newable)
			throws DataAccessException {
		ArmDailyProductReporter me = get(id);
		if (me != null && me.getResearch() != null) {
			return me.getResearch().getData();
		} else
			return getNewDraft(me);
	}

	@Override
	public byte[] getNewDraft(ArmDailyProductReporter me) {
		if (me == null)
			return loadEmptyTemplate("product");
		ArmDailyProductReporter last = me.getLast();
		if (last == null || (last != null && (last.getResearch() == null))) {
			return loadEmptyTemplate("product");
		}

		return reInitiResearch(last.getResearch().getData());

	}

	@Override
	public byte[] loadEmptyTemplate(String template) {
		if(template==null)throw new IllegalStateException("Excle 模版名称不能为空");
		InputStream ins = null;
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		try {
			org.springframework.core.io.Resource res = resourceLoader
					.getResource(String.format("classpath:%s.xls",template));
			ins = res.getInputStream();
			IOUtils.copy(ins, bos);
		} catch (IOException e) {
			logger.error(e);
			e.printStackTrace();
		} finally {
			try {
				ins.close();
			} catch (IOException e) {
				logger.error(e);
				e.printStackTrace();
			}
		}
		return bos.toByteArray();
	}

	@Override
	public byte[] reInitiResearch(byte[] data) {
		if (data == null || data.length == 0)
			return new byte[0];

		ByteArrayInputStream bis = new ByteArrayInputStream(data);
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		try {
			ResearchRowConverter rec = new ResearchRowConverter();
			Workbook wb = new HSSFWorkbook(bis);
			Workbook wb2 = new HSSFWorkbook();

			int sheetCount = wb.getNumberOfSheets();
			for (int s = 0; s < sheetCount; s++) {
				Sheet sheet = wb.getSheetAt(s);
				Sheet sheet2 = wb2.createSheet();

				Iterator<Row> rowItr = sheet.rowIterator();

				int rowIndex = 0;
				while (rowItr.hasNext()) {
					Row row = rowItr.next();
					rowIndex = row.getRowNum();
					// Row nrow = rec.convert(row);
					Row row2 = sheet2.createRow(row.getRowNum());

					Iterator<Cell> citr = row.cellIterator();
					while (citr.hasNext()) {
						Cell c = citr.next();
						// ExcelUtil.copyAndCreateCell(c, row2);
						Cell cr = row2.createCell(c.getColumnIndex());

						if (c.getCellType() == Cell.CELL_TYPE_STRING) {
							cr.setCellValue(c.getStringCellValue());							
						}
						if (c.getCellType() == Cell.CELL_TYPE_NUMERIC) {
							cr.setCellValue(c.getNumericCellValue());
						}		
						if (c.getCellType() == Cell.CELL_TYPE_FORMULA){
							cr.setCellValue(c.getNumericCellValue());
						}

						if (cr.getColumnIndex() < 2) {
							sheet2.setColumnWidth(cr.getColumnIndex(), 25 * 256);
						} else {
							sheet2.setColumnWidth(cr.getColumnIndex(), 15 * 256);
						}
						
					}
					if (row2.getRowNum() < 2)
						continue;
					rec.convert(row2);
					//logger.info(ExcelUtil.rowString(row2));
				}
				// 为以后产品增加空余行
				for (int r = rowIndex + 1; r < rowIndex + 20; r++) {
					Row row2 = sheet2.createRow(r);
					Cell c = row2.createCell(0, Cell.CELL_TYPE_STRING);
					c.setCellValue("   ");
					c = row2.createCell(1, Cell.CELL_TYPE_STRING);
					c.setCellValue("   ");
					for (int rc = 2; rc < 17; rc++) {
						c = row2.createCell(rc, Cell.CELL_TYPE_NUMERIC);
						c.setCellValue(0D);
					}
					c = row2.createCell(17);
					c.setCellValue("   ");
					rec.convert(row2);
				}

			}

			wb2.write(bos);

		} catch (IOException e) {
			logger.error(e.toString());
			e.printStackTrace();
		}
		return bos.toByteArray();
	}

	@Override
	public void updateResearch(String id) throws DataAccessException {
		ArmDailyProductReporter ar = get(id);
		if (ar == null) {
			logger.warn(" id with  '" + id
					+ "' not found for ArmDailyProductReporter ");
			return;
		}		
	      
		if (ar.isFinished()) {
			logger.warn("报表 " + ar.getId() + " 已经提交,不能再次修改");
			return;
		}

		byte[] content = SOAOfficeUtil.parseSOAOfficeStream();

		OfficeDocument ott = ar.getResearch();
		if (ott == null) {
			ott = new OfficeDocument();
			ott.setExt("xls");
			ott.setType(AttachmentType.EXCEL);
			ar.setResearch(ott);
		}
		evaluateFormulas(content);
		ott.setData(content);

	}

	/**
	 * @param data
	 *            excel 内容
	 * @return 计算公式后的数据流
	 * 
	 * */
	@Override
	public byte[] evaluateFormulas(byte[] data) {
		if (data == null || data.length == 0)
			return new byte[0];

		ByteArrayInputStream bis = new ByteArrayInputStream(data);
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		try {

			HSSFWorkbook wb = new HSSFWorkbook(bis);
			HSSFFormulaEvaluator evaluator = wb.getCreationHelper()
					.createFormulaEvaluator();
			evaluator.evaluateAll();
			RowConverter rec = new EvaluateFormulaConverter(evaluator);
			int sheetCount = wb.getNumberOfSheets();
			for (int s = 0; s < sheetCount; s++) {
				Sheet sheet = wb.getSheetAt(s);
				Iterator<Row> rowItr = sheet.rowIterator();
				while (rowItr.hasNext()) {

					rec.convert(rowItr.next());
				}
			}
			wb.write(bos);
		} catch (IOException e) {
			logger.error(e.toString());
			e.printStackTrace();
		}

		return bos.toByteArray();
	}

	@Override
	@SuppressWarnings("unchecked")
	public byte[] collateDaily(int year, int month, int date)
			throws DataAccessException {

		String hql = String
				.format("from  %s  r where r.finished is true and year(r.createDate)=%d and month(r.createDate)=%d and day(r.createDate)=%d group by r.department",
						table(), year, month, date);
		List<ArmDailyProductReporter> list = query(hql).list();
		byte[] data = collateDaily(list);
		CollationDailyReport crpt = getCollationDailyReport(year, month, date);
		if (crpt == null)
			crpt = new CollationDailyReport();
		crpt.setName(year + "-" + month + "-" + date + "综合生产日报");
		crpt.setExt(AttachmentType.EXCEL.toString());
		crpt.setType(AttachmentType.EXCEL);
		crpt.setData(data);
		return data;

	}

	@Override
	@SuppressWarnings("rawtypes")
	public CollationDailyReport getCollationDailyReport(int year, int month,
			int date) {
		String hql = "from "
				+ CollationDailyReport.class.getName()
				+ " cr where cr.year=:year and cr.month=:month and cr.date=:date";
		Iterator itr = query(hql).setInteger("year", year)
				.setInteger("month", month).setInteger("date", date).iterate();
		return (CollationDailyReport) (itr.hasNext() ? itr.next() : null);
	}

	/**
	 * @return 返回一个字节数组，其实代表一个excel 文件
	 * @param Collection
	 *            &lt;ArmDailyProductReporter&gt; 每一个报表会当作一个sheet
	 * */
	@Override
	public byte[] collateDaily(Collection<ArmDailyProductReporter> rpts) {
		
		if(CollectionUtils.isEmpty(rpts)) return loadEmptyTemplate("collote");;
		
		Workbook wb = new HSSFWorkbook();

		ByteArrayOutputStream os = new ByteArrayOutputStream();
		String[] title = { "代码", "名称", "单位", "年初", "月初", "今日动工", "动工累计",
				"今日合格", "合格累计", "今日废品", "废品累计", "今日试销", "试销累计", "期末结存", "备注" };
		DataItemType[] requiredDataTypes = { DataItemType.Action,
				DataItemType.Passed, DataItemType.Waster, DataItemType.Test };
		int cellWidth = 15 * 256;
		CellStyle cs = wb.createCellStyle();
		cs.setAlignment(CellStyle.ALIGN_CENTER);
		Font ft = wb.createFont();
		ft.setFontHeight((short) 240);
		ft.setFontName("宋体");
		ft.setBoldweight((short) 900);
		cs.setFont(ft);

		try {
			for (ArmDailyProductReporter r : rpts) {
				findResearchItems(r);
				Department dept = r.getDepartment();
				String sheetName = dept.getName();
				Sheet sheet = wb.createSheet(sheetName);
				
				Row firstRow = sheet.createRow(0);
				// 添加表头

				for (int i = 0; i < title.length; i++) {

					Cell cell = firstRow.createCell(i);
					cell.setCellValue(title[i]);
					cell.setCellStyle(cs);
					sheet.setColumnWidth(i, cellWidth);
				}

				Collection<ArmItem> aims = r.getArmItems();

				// 根据产品类型映射产品

				Map<ProductType, Collection<ArmItem>> maps = dataItemUtil
						.mapArmItems(aims);
				maps.put(ProductType.科研产品, r.getResearchItems());

				int row = 1;

				// proceed for xls row
				for (Map.Entry<ProductType, Collection<ArmItem>> itemEntry : maps
						.entrySet()) {
					ProductType pType = itemEntry.getKey();
					Collection<ArmItem> ivalues = itemEntry.getValue();
					Row headRow = sheet.createRow(row);
					headRow.setRowStyle(cs);
					Cell hcell = headRow.createCell(0, Cell.CELL_TYPE_STRING);
					hcell.setCellValue(pType.toString() + " ");
					hcell.setCellStyle(cs);					
					sheet.setColumnWidth(0, cellWidth);
					for (int j = 1; j < 16; j++) {

						headRow.createCell(j, Cell.CELL_TYPE_STRING)
								.setCellValue("  ");
						sheet.setColumnWidth(j, cellWidth);
					}

					row++;
					// proceed for row column
					for (ArmItem ai : ivalues) {
						Product pdt = ai.getHost();

						Row theRow = sheet.createRow(row);

						int cindex = 0;

						// 代码
						theRow.createCell(cindex++).setCellValue(pdt.getCode());

						// 名称
						theRow.createCell(cindex++).setCellValue(pdt.getName());

						// 单位
						theRow.createCell(cindex++).setCellValue(
								pdt.getPriceUnit());

						// 年初结存
						Double fd = dataItemUtil.getDataItemAtom(ai,
								DataItemType.ForwardStore);
						theRow.createCell(cindex++).setCellValue(fd);

						// 月初结存
						fd = dataItemUtil.getDataItemAccumulation(ai,
								DataItemType.ForwardStore);
						theRow.createCell(cindex++).setCellValue(fd);

						// 添加数据列
						sheet.autoSizeColumn(cindex, true);
						for (DataItemType dtype : requiredDataTypes) {
							Cell dcell = theRow.createCell(cindex++);
							Double d = dataItemUtil.getDataItemAtom(ai, dtype);
							dcell.setCellValue(d);
							sheet.setColumnWidth(cindex, cellWidth);

							dcell = theRow.createCell(cindex++);
							d = dataItemUtil.getDataItemAccumulation(ai, dtype);
							dcell.setCellValue(d);
							sheet.setColumnWidth(cindex, cellWidth);
						}

						// 添加期末数
						fd = dataItemUtil.getDataItemAtom(ai,
								DataItemType.FinalStore);
						theRow.createCell(cindex++).setCellValue(fd);

						// 添加备注列
						theRow.createCell(cindex++)
								.setCellValue(ai.getRemark());
						sheet.setColumnWidth(cindex, cellWidth);
						sheet.autoSizeColumn(0);
						sheet.autoSizeColumn(1);
						row++;
					}

				}

			}
			wb.write(os);

		} catch (IOException e) {
			e.printStackTrace();
		} finally {

		}

		return os.toByteArray();

	}

	
	
	
	@Override
	public boolean publish(int year, int month, int day)
			throws DataAccessException, InterruptedException,
			ExecutionException, IOException, DocumentException {

		CollationDailyReport office = this.getCollationDailyReport(year, month,
				day);
		if (office == null)
			return false;

		ByteArrayInputStream input = new ByteArrayInputStream(office.getData());
		String name = String.format("%d年%d月%d日生产日报", year, month, day);
		newsService.create(dailyCatalogId, new Date(), input, name);
		return true;

	}

	@Override
	public boolean publish(DateTime cal) throws DataAccessException,
			InterruptedException, ExecutionException, IOException,
			DocumentException {
		int year = cal.getYear();
		int month = cal.getMonthOfYear();
		int date = cal.getDayOfMonth();
		return publish(year, month, date);
	}

	
	@Override
	public byte[] collateDaily(DateTime cal) throws DataAccessException {
		cal = cal == null ? DateTime.now() : cal;
		int year = cal.getYear();
		int month = cal.getMonthOfYear();
		int date = cal.getDayOfMonth();
		return collateDaily(year, month, date);

	}

	@Override
	@Transactional
	public void updateCollate(DateTime cal) throws DataAccessException {
		byte[] content = SOAOfficeUtil.parseSOAOfficeStream();
		int year = cal.getYear();
		int month = cal.getMonthOfYear();
		int date = cal.getDayOfMonth();
		CollationDailyReport od = getCollationDailyReport(year, month, date);
		od.setType(AttachmentType.综合日报);
		od.setCreateDate(DateTime.now());
		od.setData(content);
	}

	@Override
	public void checkArmitems(byte[] content, Department dept, RowWatcher rw) {
		if (content == null || content.length == 0)
			return;
		ByteArrayInputStream bis = new ByteArrayInputStream(content);
		try {
			HSSFWorkbook wb = new HSSFWorkbook(bis);
			int sheetCount = wb.getNumberOfSheets();
			for (int s = 0; s < sheetCount; s++) {
				Sheet sheet = wb.getSheetAt(s);
				Iterator<Row> rowItr = sheet.rowIterator();
				int hidx = 0;
				while (rowItr.hasNext()) {
					Row row = rowItr.next();
					if (hidx < 2) {
						hidx += 1;
						continue;
					}
					rw.accept(row);
				}
			}

		} catch (IOException e) {
			logger.error(e);
			e.printStackTrace();
		}
	}

	@Resource
	public void setPlanningService(ArmMonthlyPlanService planningService) {
		this.planningService = planningService;
	}

	@Override
	public ArmDailyProductReporter get(String id) throws DataAccessException {
		if (id == null)	throw new NullPointerException(" daily report id must not be null");
		ArmDailyProductReporter rpt = super.get(id);
		if (rpt == null) throw new ReportException(" the id with "+id+" can not be found in hibernate"); 
		afterGetration(rpt);	
		return rpt;
	}

	/**
	 * 查找计划项
	 * */
	@Transactional(isolation = Isolation.READ_UNCOMMITTED, readOnly = true)
	void findPlanValue(ArmDailyProductReporter rpt, DateTime cdate) {

		int year = cdate.getYear();
		int month = cdate.getMonthOfYear();
		Collection<MonthPlanning> mps = planningService.find(year, month);

		
		if (CollectionUtils.isEmpty(mps)) {
			logger.warn("年 :" + year + " 月: " + month + " 没有下计划");
			return;
		}

		Map<String, List<ArmItem>> itemsMap = rpt.getClassifiedItems();
		for (Map.Entry<String, List<ArmItem>> ientry : itemsMap.entrySet()) {

			List<ArmItem> armItems = ientry.getValue();
			Map<String, Collection<Double>> planMapper = Maps.newHashMap();
			// map the plan data , code as key;
			for (MonthPlanning p : mps) {
				for (MonthPlanningItem mpi : p.getDataItems()) {
					Product pdt = mpi.getOwner();
					if (pdt == null)
						continue;
					String code = pdt.getCode();
					Collection<Double> values = planMapper.get(code);
					if (values == null) {
						values = Lists.newArrayList();
						planMapper.put(code, values);
					}
					values.add(mpi.getFinalValue());
				}
			}

			// reduce
			for (Map.Entry<String, Collection<Double>> mentry : planMapper
					.entrySet()) {
				Double val = 0D;
				for (Double td : mentry.getValue())
					val += td;

				ArmItem example = new ArmItem(mentry.getKey());
				ArmItem target = reportUtil.findByCode(armItems, example);

				if (target != null) {
					target.setMonthPlan(val);
				}

			}
		}

	}

	void markActionedArmItem(ArmDailyProductReporter rpt) {
		Map<String, List<ArmItem>> itemsMap = rpt.getClassifiedItems();
		for (Map.Entry<String, List<ArmItem>> mentry : itemsMap.entrySet()) {
			List<ArmItem> items = mentry.getValue();
		    outitem:for (ArmItem ai : items) {
				Map<String, DataItem> dis = ai.getDataItems();
				DataItemType[] dts = new DataItemType[] { DataItemType.Action,
						DataItemType.Passed, DataItemType.Waster,
						DataItemType.Test };
				for (DataItemType dt : dts) {
					DataItem dd = dis.get(dt.toString());
					if (dd != null) {
						Double atom = dd.getAtomValue();
						boolean actioned = !new Double(0D).equals(atom);						
						if(actioned){
						    ai.setActioned(actioned);
						    continue outitem;
						}
					}
				}
			}
		}

	}

	/**
	 * 综合科研项目
	 * */
	void findResearchItems(ArmDailyProductReporter rpt) {
		if (rpt == null)
			return;
		OfficeDocument rsch = rpt.getResearch();
		final Collection<ArmItem> ais = Lists.newArrayList();
		if (rsch != null) {
			// 如果已经添加过科研产品
			checkArmitems(
					rsch.getData(),
					rpt.getDepartment(),
					new ArmItemResearchRowWatcher(ais, productService, rpt
							.getDepartment(), dataItemUtil, ProductType.科研产品)

			);

			rpt.setResearchItems(ais);
		}
	}

	/**
	 * 更新报表的结存数据
	 * 
	 * @param t
	 *            日报对象
	 * */
	void updateDailyStore(ArmDailyProductReporter t) {
		if (t == null)return;
		DateTime dt = t.getCreateDate();
		finalStoreVistor.starup(t.getDepartment(),dt==null?DateTime.now():dt);
		for (ArmItem ai : t.getArmItems()) {
			if (ai == null)continue;
			finalStoreVistor.visite(ai);
		}
	}

	@Resource(name = ReportConstant.DailyFinalStroeVistor)
	public void setFinalStoreVistor(
			ArmItemFinalStoreDailyVisitor finalStoreVistor) {
		this.finalStoreVistor = finalStoreVistor;
	}

	@Override
	public Collection<ArmDailyProductReporter> getDailyCollation(int year,
			int month, int date) throws DataAccessException {
		String hql = String
				.format("from  %s  r where year(r.createDate)=%d and month(r.createDate)=%d and day(r.createDate)=%d group by r.department",
						table(), year, month, date);
		List<ArmDailyProductReporter> list = query(hql).list();
		for (ArmDailyProductReporter rpt : list) {
			classifiedReport(rpt);
			findResearchItems(rpt);
		}
		return list;
	}

	@Override
	public ArmDailyProductReporter get(int year, int month, int date,
			Department department) throws DataAccessException {
		String hql = String
				.format("from  %s  r where year(r.createDate)=%d and month(r.createDate)=%d and day(r.createDate)=%d and r.department=:dept",
						table(), year, month, date);
		Iterator<ArmDailyProductReporter> itr = query(hql).setParameter("dept",
				department).iterate();
		ArmDailyProductReporter rpt = itr.hasNext() ? itr.next() : null;
		if (rpt != null) {
			classifiedReport(rpt);
			findResearchItems(rpt);
			findPlanValue(rpt, rpt.getCreateDate());
			markActionedArmItem(rpt);
		}

		return rpt;
	}

	@Override
	public Page query(org.jackysoft.query.Query qc, Integer pindex, Integer rows)
			throws DataAccessException {
		return super.query(qc, pindex, rows);

	}

	
	@Override
	public boolean resetable(DateTime today) {
		int year = today.getYear();
		int month = today.getMonthOfYear();
		int date = today.getDayOfMonth();
		DailyResetDate dr = resetDateService.getDailyResetDate(year, month);
		if (dr == null)
			return super.resetable(today);
		else {

			DateTime first = dr.getFirstDate();
			if (first == null)
				throw new IllegalStateException(year + "年" + month
						+ "月设置了指定日期,但是 firstDate 参数丢失");
			else {
				int fdate = first.getDayOfMonth();
				return date == fdate;
			}
		}
	}

	
	@Override
	@Transactional(isolation = Isolation.READ_UNCOMMITTED, readOnly = true)
	public Map<String, Double> fetchCurrentComplated(DateTime createDate)
			throws DataAccessException {
		final Map<String, Double> items = Maps.newHashMap();
		int year = createDate.getYear();
		int month = createDate.getMonthOfYear();
		for (int m = 0; m <= month; m++) {
			DailyResetDate drd = resetDateService.getDailyResetDate(year, m);
			DateTime lastDate = drd.getLastDate();
			int date = 26;
			if (lastDate != null)
				date = lastDate.getDayOfMonth();
			Collection<ArmDailyProductReporter> das = getDailyCollation(year,
					month, date);
			for (ArmDailyProductReporter dar : das) {
				mapCurrentValue(dar, items);
			}
		}
		int todate = createDate.getDayOfMonth();
		// 今天日报
		Collection<ArmDailyProductReporter> das = getDailyCollation(year,
				month, todate);
		for (ArmDailyProductReporter dar : das) {
			mapCurrentValue(dar, items);
		}
		return items;
	}

	void mapCurrentValue(ArmDailyProductReporter dar, Map<String, Double> items) {
		List<ArmItem> ais = dar.getArmItems();
		for (ArmItem ai : ais) {
			if (ai == null)
				continue;
			String code = ai.getHost().getCode();
			Double passedVal = dataItemUtil.getDataItemAccumulation(ai,
					DataItemType.Passed);
			Double val = items.get(code);
			if (val == null) {
				items.put(code, passedVal);
			} else {
				items.put(code, val + passedVal);
			}
		}
	}

	@Override
	@Transactional(isolation = Isolation.READ_UNCOMMITTED, readOnly = true)
	public FileInfo download(String id) throws Exception {

		ArmDailyProductReporter rpt = get(id);
		Collection<ArmDailyProductReporter> rpts = Lists.newArrayList();
		rpts.add(rpt);
		byte[] data = this.collateDaily(rpts);
		FileInfo finfo = new FileInfo(rpt.getCreateDate().toString("yyyy-MM-dd")+"-"+rpt.getDepartment().getName()+"-生产日报.xls", "/", "xls", data);
		return finfo;
	}

	@Override
	public void updateForwardStore(final int year,final int month) {
		Callable<String> cs = 	new Callable<String>(){

			@Override
			public String call() throws Exception {
				Collection<ArmDailyProductReporter>  rpts = getsOfMonth(year, month);
				for(ArmDailyProductReporter rpt : rpts){
				   updateDailyStore(rpt);
				}
				return null;
			}
			
		};
		
		ExecutorService es  = Executors.newSingleThreadExecutor();
		es.submit(cs);
		
		
		
	}

	@Override
	@SuppressWarnings({ "rawtypes", "unchecked" })
    public Collection<ArmDailyProductReporter> getsOfMonth(int year, int month) {
		String hql =String.format(
				"from %s r where year(r.createDate)=%d and month(r.createDate)=%d"
				,table(),year,month);
		List list = query(hql).list();
		return list;
	}

	@Override
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public Collection<ArmDailyProductReporter> getsOfMonth(int year, int month,
			Department dept) {
		String hql =String.format(
				"from %s r.department.id='%s' and  r where year(r.createDate)=%d and month(r.createDate)=%d"
				,table(),dept.getId(),year,month);
		List list = query(hql).list();
		return list;
	}
	
	@Override
	public ArmDailyProductReporter getByTopDate(DateTime tdate,
			Department department) throws DataAccessException {
		ArmDailyProductReporter t =  get(tdate, department);
		if(t!=null) return t;		
		String hql = String
				.format("select r.id as id from %s r WHERE r.department.id='%s'"
						+" AND r.createDate="
						+" (" 
							+" SELECT MAX(u.createDate) FROM %s u"
							+" WHERE DATEDIFF(DATE('%s'),(DATE(u.createDate)))>0" 
							+" AND u.department.id='%s'"
						+")"
                        ,table()
                        ,department.getId()
                        ,table()
                        ,tdate.toString("yyyy-MM-dd")
                        ,department.getId()
						);
		Query q = query(hql);
		Iterator itr = q.iterate();
		Object rst = itr.hasNext()?itr.next():null;
		logger.info("the last report is "+rst);
		if(rst==null)return null;
		ArmDailyProductReporter rpt =  get(rst.toString());
		//afterGetration(rpt);	
		return rpt;
	}
	
	private void afterGetration(ArmDailyProductReporter rpt){
		if(rpt==null)return;
		findResearchItems(rpt);
		findPlanValue(rpt, rpt.getCreateDate());
		markActionedArmItem(rpt);
	}
	
	@Resource
	public void setResetDateService(DailyResetDateService resetDateService) {
		this.resetDateService = resetDateService;
	}
	
	@Resource(name=ReportConstant.ArmItemRegionEqualPredicate)
	public void setRegionPredicate(ArmItemRegionEqualsPredicate regionPredicate) {
		this.regionPredicate = regionPredicate;
	}	
	
	@Resource(name = ReportConstant.DailyAccumulateVisitor)
	public void setAccumulateVisitor(ArmItemVisitor accumulateVisitor) {
		super.setAccumulateVisitor(accumulateVisitor);
	}
	@Resource
	public void setNewsService(NewsInfoService newsService) {
		this.newsService = newsService;
	}

	

}
